package com.avecsys.quotemanager.dao.user;

import java.sql.SQLException;
import java.util.List;
import java.util.Set;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Criteria;
import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Expression;
import org.hibernate.criterion.Restrictions;
import org.springframework.orm.hibernate3.HibernateCallback;

import com.avecsys.quotemanager.dao.common.BaseDAOImpl;
import com.avecsys.quotemanager.dao.common.EnumDBRecordStatus;
import com.avecsys.quotemanager.dao.common.EnumTransactionStatus;
import com.avecsys.quotemanager.exception.BusinessException;
import com.avecsys.quotemanager.exception.DAOException;
import com.avecsys.quotemanager.pojos.BuyerMasterPojo;
import com.avecsys.quotemanager.pojos.BuyerUsersPojo;
import com.avecsys.quotemanager.pojos.SupplierMasterPojo;
import com.avecsys.quotemanager.pojos.SupplierUsersPojo;
import com.avecsys.quotemanager.pojos.SystemUsersPojo;
import com.avecsys.quotemanager.pojos.UserMasterPojo;
import com.avecsys.quotemanager.utils.TransactionStatus;

public class UserMasterDAOImpl extends BaseDAOImpl implements UserMasterDAO
{

	private static final Log log = LogFactory.getLog(UserMasterDAOImpl.class);

	/**
	 * Method to mark the supplier user information as deleted
	 * 
	 * @param supplierUsersPojo
	 * @return TransactionStatus
	 */
	@Override
	public TransactionStatus deleteSupplierUser(final SupplierUsersPojo supplierUsersPojo)
			throws DAOException
	{

		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.DELETE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Mark Supplier user as deleted
					supplierUsersPojo.setStatus(EnumDBRecordStatus.DELETED.status());
					session.update(supplierUsersPojo);
					// If Supplier User is not associated as buyer for another
					// supplier then mark the userMasterPojo status as deleted
					Set<BuyerUsersPojo> buyerUsersPojoSet = supplierUsersPojo.getUserMasterPojo()
							.getBuyerUsersPojo();
					if ((buyerUsersPojoSet != null) && (buyerUsersPojoSet.size() == 0))
					{
						supplierUsersPojo.getUserMasterPojo().setStatus(
								EnumDBRecordStatus.DELETED.status());
						session.update(supplierUsersPojo.getUserMasterPojo());
					}
					else
					{
						log.info("The supplier user "
								+ supplierUsersPojo.getUserMasterPojo().getEmail()
									+ " is associated as Buyer to another supplier. So not marking as deleted in supplier user delete operation.");
					}
					return supplierUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.DELETE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	/**
	 * Method to return all userMasterPojo matching the email criteria with active status associated as
	 * Buyer
	 * 
	 * @param email
	 * @return List<UserMasterPojo>
	 * @throws DAOException
	 */
	@Override
	public List<UserMasterPojo> findAllActiveBuyerUsersByEmail(final String email) throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<UserMasterPojo>>()
		{
			@Override
			public List<UserMasterPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query q = session.createQuery("from UserMasterPojo userMasterPojo left join fetch userMasterPojo.buyerUsersPojo buyerUsersPojo where userMasterPojo.status=:userStatus and buyerUsersPojo.status=:buyerUserStatus and userMasterPojo.email=:email");
				q.setString("userStatus", EnumDBRecordStatus.ACTIVE.status());
				q.setString("buyerUserStatus", EnumDBRecordStatus.ACTIVE.status());
				q.setString("email", email);
				return q.list();
			}
		});
	}

	/**
	 * Method to return all userMasterPojo matching the email criteria with active status associated as
	 * Supplier
	 * 
	 * @param email
	 * @return List<UserMasterPojo>
	 * @throws DAOException
	 */
	@Override
	public List<UserMasterPojo> findAllActiveSupplierUsersByEmail(final String email)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<UserMasterPojo>>()
		{
			@Override
			public List<UserMasterPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				Query q = session.createQuery("from UserMasterPojo userMasterPojo left join fetch userMasterPojo.supplierUsersPojo supplierUsersPojo where userMasterPojo.status=:userStatus and supplierUsersPojo.status=:supplierUserStatus and userMasterPojo.email=:email");
				q.setString("userStatus", EnumDBRecordStatus.ACTIVE.status());
				q.setString("supplierUserStatus", EnumDBRecordStatus.ACTIVE.status());
				q.setString("email", email);
				return q.list();
			}
		});
	}

	/**
	 * Method to return all the Administrator users for a supplier
	 * 
	 * @param supplierMasterPojo
	 * @return boolean
	 * @throws DAOException
	 */
	@Override
	public List<UserMasterPojo> findAllSupplierAdminUsers(final SupplierMasterPojo supplierMasterPojo)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<UserMasterPojo>>()
		{
			@Override
			public List<UserMasterPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				final Criteria criteria = session.createCriteria(SupplierUsersPojo.class);
				criteria.add(Restrictions.eq(
						"supplierMasterPojo.supplierId",
							supplierMasterPojo.getSupplierId()));
				criteria.add(Restrictions.eq("isAdmin", Boolean.TRUE.toString()));
				criteria.add(Restrictions.eq("status", EnumDBRecordStatus.ACTIVE.status()));
				return criteria.list();
			}
		});
	}

	/**
	 * Method to find all the list of users for a supplier
	 * 
	 * @param supplierMasterPojo
	 * @return List<UserMasterPojo>
	 * @throws BusinessException
	 */
	@Override
	public List<SupplierUsersPojo> findAllUsersBySupplier(final SupplierMasterPojo supplierMasterPojo)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<SupplierUsersPojo>>()
		{
			@Override
			public List<SupplierUsersPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				final Criteria criteria = session.createCriteria(SupplierUsersPojo.class);
				criteria.add(Restrictions.eq(
						"supplierMasterPojo.supplierId",
							supplierMasterPojo.getSupplierId()));
				criteria.add(Restrictions.eq("status", EnumDBRecordStatus.ACTIVE.status()));
				return criteria.list();
			}
		});
	}

	/**
	 * Method to save Supplier User Information
	 * 
	 * @param supplierUsersPojo
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus saveSupplierUser(final SupplierUsersPojo supplierUsersPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.SAVE_SUCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Save User Information
					session.save(supplierUsersPojo.getUserMasterPojo());
					// 2. Save Supplier User Information
					session.save(supplierUsersPojo);
					return supplierUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.SAVE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;

	}

	/**
	 * Method to Update Supplier User Information
	 * 
	 * @param supplierUsersPojo
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus updateSupplierUser(final SupplierUsersPojo supplierUsersPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.UPDATE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Update User Information
					session.update(supplierUsersPojo.getUserMasterPojo());
					// 2. Update Supplier User Information
					session.update(supplierUsersPojo);
					return supplierUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.UPDATE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}
	/**
	 * Method to Update Buyer User Information
	 * 
	 * @param buyerUsersPojo
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus updateBuyerUser(final BuyerUsersPojo buyerUsersPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.UPDATE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Update User Information
					session.update(buyerUsersPojo.getUserMasterPojo());
					// 2. Update Supplier User Information
					session.update(buyerUsersPojo);
					return buyerUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.UPDATE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}
	
	/**
	 * Method to save Supplier User Information
	 * 
	 * @param buyerUsersPojo
	 * @return TransactionStatus
	 * @throws DAOException
	 */
	@Override
	public TransactionStatus saveBuyerUser(final BuyerUsersPojo buyerUsersPojo)
			throws DAOException
	{
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.SAVE_SUCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Save User Information
					session.save(buyerUsersPojo.getUserMasterPojo());
					// 2. Save Supplier User Information
					session.save(buyerUsersPojo);
					return buyerUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.SAVE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;

	}

	@Override
	public TransactionStatus deleteBuyerUser(final BuyerUsersPojo buyerUsersPojo) throws DAOException
	{

		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.DELETE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Mark buyer user as deleted
					buyerUsersPojo.setStatus(EnumDBRecordStatus.DELETED.status());
					session.update(buyerUsersPojo);
					/*// If Supplier User is not associated as buyer for another
					// supplier then mark the userMasterPojo status as deleted
					Set<BuyerUsersPojo> buyerUsersPojoSet = supplierUsersPojo.getUserMasterPojo()
							.getBuyerUsersPojo();
					if ((buyerUsersPojoSet != null) && (buyerUsersPojoSet.size() == 0))
					{
						supplierUsersPojo.getUserMasterPojo().setStatus(
								EnumDBRecordStatus.DELETED.status());
						session.update(supplierUsersPojo.getUserMasterPojo());
					}
					else
					{
						log.info("The supplier user "
								+ supplierUsersPojo.getUserMasterPojo().getEmail()
									+ " is associated as Buyer to another supplier. So not marking as deleted in supplier user delete operation.");
					}*/
					return buyerUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.DELETE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	@Override
	public List<BuyerUsersPojo> findAllUsersByBuyer(final BuyerMasterPojo buyerMasterPojo)
			throws DAOException
	{
		return getHibernateTemplate().execute(new HibernateCallback<List<BuyerUsersPojo>>()
		{
			@Override
			public List<BuyerUsersPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				final Criteria criteria = session.createCriteria(BuyerUsersPojo.class);
				criteria.add(Restrictions.eq(
						"buyerMasterPojo.buyerId",
						buyerMasterPojo.getBuyerId()));
				criteria.add(Restrictions.eq("status", EnumDBRecordStatus.ACTIVE.status()));
				return criteria.list();
			}
		});
	}

	@Override
	public TransactionStatus deleteSystemUser(final SystemUsersPojo systemUsersPojo)
			throws DAOException {
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.DELETE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Mark System user as deleted
					systemUsersPojo.setStatus(EnumDBRecordStatus.DELETED.status());
					session.update(systemUsersPojo);
					return systemUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.DELETE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;

	}

	@Override
	public TransactionStatus updateSystemUser(final SystemUsersPojo systemUsersPojo)
			throws DAOException {
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.UPDATE_SUCCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Update User Information
					session.update(systemUsersPojo.getUserMasterPojo());
					// 2. Update System User Information
					session.update(systemUsersPojo);
					return systemUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.UPDATE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	@Override
	public TransactionStatus saveSystemUser(final SystemUsersPojo systemUsersPojo)
			throws DAOException {
		TransactionStatus transactionStatus = new TransactionStatus(
				EnumTransactionStatus.SAVE_SUCESS.ordinal());
		try
		{
			getHibernateTemplate().execute(new HibernateCallback<Object>()
			{
				@Override
				public Object doInHibernate(Session session) throws HibernateException, SQLException
				{
					// 1. Save User Information
					session.save(systemUsersPojo.getUserMasterPojo());
					// 2. Save System User Information
					session.save(systemUsersPojo);
					return systemUsersPojo;
				}
			});
		}
		catch (Exception e)
		{
			log.error(e);
			transactionStatus.setStatus(EnumTransactionStatus.SAVE_FAIL.ordinal());
			throw new DAOException(e);
		}
		return transactionStatus;
	}

	@Override
	public List<SystemUsersPojo> findAllUsersForSystem(final Long companyId) throws DAOException {
		return getHibernateTemplate().execute(new HibernateCallback<List<SystemUsersPojo>>()
		{
			@Override
			public List<SystemUsersPojo> doInHibernate(Session session) throws HibernateException,
					SQLException
			{
				final Criteria criteria = session.createCriteria(SystemUsersPojo.class);
				criteria.add(Restrictions.eq(
						"companyMasterPojo.companyId",companyId));
				criteria.add(Restrictions.eq("status", EnumDBRecordStatus.ACTIVE.status()));
				return criteria.list();
			}
		});
	}
}
